/** @file b_renderer.h
	@brief Geometry batch renderer */

#ifndef G3_BATCH_RENDERER_H
#define G3_BATCH_RENDERER_H

#include <boost/thread/thread.hpp>
#include <deque>
#include <set>

#include "log.h"

#include "singleton.h"
#include "timer.h"

#include "vbo.h"
#include "displaylist.h"

#include "render/r_frustum.h"
#include "render/batch/b_sorter.h"

namespace G3 {

/** @class SPATIAL_RENDERABLE
	@brief Renderable spatial partitioning object interface */
class SPATIAL_RENDERABLE {
    public:
		/**
			@brief A dummy constructor
		*/
		SPATIAL_RENDERABLE () {}
		/**
			@brief And a destructor 4 dummiez
		*/
		virtual ~SPATIAL_RENDERABLE () {}
        /**
            @brief Updates the batches
            @param[in] frust Reference to the view frustum
        */
        virtual void update (const G3::FRUSTUM *frust) = 0;
};

/** @class BATCH_RENDERER
	@brief Geometry batch renderer singleton class */
class BATCH_RENDERER: public G3::SINGLETON<BATCH_RENDERER> {
    public:
        /**
            @brief Constructor that ... uhm, NULLs the pointers
        */
        BATCH_RENDERER ();
        /**
            @brief Well, a destructor
        */
        ~BATCH_RENDERER ();

        /** A log pointer */
        G3::LOG *log;

        /** A set of spatial partitioning objects to be rendered */
        std::set<boost::shared_ptr<SPATIAL_RENDERABLE> > spatial_objs;

        /** Rendering optimizations */
        enum OPTIMIZATION {
            O_NONE = 0, /** No optimization */
            O_DISPLAYLISTS = 1, /** Compile into displaylists */
            O_VBO = 2 /** Upload onto the graphics card via VBO's */
        };

        /** How's the rendering optimized ? */
        OPTIMIZATION optimization;

        /** The rendering frustum */
        G3::FRUSTUM *frustum;

        /** Batch renderer's own fps counter */
        G3::FPS_COUNTER fps_counter;

        /** Number of batches currently rendered */
        long batches_rendered;

        /**
            @brief Attaches a spatial partitioning system to the renderer
            @param[in] spatial Pointer to the system
        */
        void attach (const boost::shared_ptr<SPATIAL_RENDERABLE> &spatial);

        /**
            @brief Initializes the renderer with a VBO and a frustum
            @param[in] vb Pointer to the new VBO
            @param[in] frust Pointer to the new FRUSTUM
            @param[in] dl Pointer to a display list object.
            display lists are used when VBO's are disabled.
            @return True on success, false on failure
        */
        bool init (G3::VBO *vb, G3::FRUSTUM *frust, G3::DISPLAYLIST *dl = NULL, G3::GEOM_POINTER *gp = NULL);

        /**
            @brief Performs the rendering
        */
        void render ();

    protected:
        /** Pointer to the currently active VBO */
        VBO *vbo;
        /** Pointer to the last VBO - for tracking VBO changes */
        VBO *last_vbo;

        DISPLAYLIST *dlist;
        DISPLAYLIST *last_dlist;

        GEOM_POINTER *gptr;
        GEOM_POINTER *last_gptr;

        /** A batch iterator */
        std::deque<BATCH *>::iterator batch_iter;
        /** A spatial renderable iterator */
        std::set<boost::shared_ptr<SPATIAL_RENDERABLE> >::iterator spatial_iter;
        /** Material change tracker */
        int last_material;
};

/** The main batch renderer singleton instance */
extern BATCH_RENDERER MainBatchRenderer;

}

#endif // G3_BATCH_RENDERER_H
